package com.langchain4j.core.flow.engine;

import com.langchain4j.core.flow.context.NodeContext;
import com.langchain4j.core.flow.node.FlowNode;
import com.langchain4j.core.flow.result.NodeResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 流程执行引擎
 */
@Slf4j
@Component
public class FlowEngine {
    
    @Autowired
    private FlowNodeRegistry nodeRegistry;
    
    @Autowired
    private FlowLogger flowLogger;
    
    /**
     * 执行流程
     * @param flowDefinition 流程定义
     * @param inputs 输入参数
     * @return 执行结果
     */
    public CompletableFuture<FlowExecutionResult> execute(FlowDefinition flowDefinition, Map<String, Object> inputs) {
        return CompletableFuture.supplyAsync(() -> {
            String executionId = generateExecutionId();
            LocalDateTime startTime = LocalDateTime.now();
            
            try {
                log.info("开始执行流程: {}, 执行ID: {}", flowDefinition.getName(), executionId);
                flowLogger.log(executionId, "engine", "开始执行流程: " + flowDefinition.getName());
                
                // 初始化执行上下文
                FlowExecutionContext context = new FlowExecutionContext(executionId, flowDefinition, inputs);
                
                // 执行流程
                FlowExecutionResult result = executeFlow(context);
                
                // 设置执行时间
                result.setStartTime(startTime);
                result.setEndTime(LocalDateTime.now());
                
                log.info("流程执行完成: {}, 执行ID: {}, 状态: {}", 
                        flowDefinition.getName(), executionId, result.getStatus());
                
                return result;
                
            } catch (Exception e) {
                log.error("流程执行异常: {}, 执行ID: {}", flowDefinition.getName(), executionId, e);
                flowLogger.logError(executionId, "engine", "流程执行异常", e);
                
                return FlowExecutionResult.builder()
                        .executionId(executionId)
                        .status(FlowExecutionResult.ExecutionStatus.FAILED)
                        .errorMessage(e.getMessage())
                        .error(e)
                        .startTime(startTime)
                        .endTime(LocalDateTime.now())
                        .build();
            }
        });
    }
    
    /**
     * 执行流程内部逻辑
     */
    private FlowExecutionResult executeFlow(FlowExecutionContext context) {
        try {
            // 获取开始节点
            FlowNode startNode = context.getFlowDefinition().getStartNode();
            if (startNode == null) {
                throw new IllegalStateException("流程没有开始节点");
            }
            
            // 执行节点
            NodeResult nodeResult = executeNode(context, startNode).get();
            
            // 构建执行结果
            FlowExecutionResult result = FlowExecutionResult.builder()
                    .executionId(context.getExecutionId())
                    .status(nodeResult.isSuccess() ? 
                            FlowExecutionResult.ExecutionStatus.SUCCESS : 
                            FlowExecutionResult.ExecutionStatus.FAILED)
                    .outputs(nodeResult.getOutputs())
                    .nodeResults(context.getNodeResults())
                    .build();
            
            if (!nodeResult.isSuccess()) {
                result.setErrorMessage(nodeResult.getErrorMessage());
                result.setError(nodeResult.getError());
            }
            
            return result;
            
        } catch (Exception e) {
            throw new RuntimeException("流程执行失败", e);
        }
    }
    
    /**
     * 执行单个节点
     */
    private CompletableFuture<NodeResult> executeNode(FlowExecutionContext context, FlowNode node) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 创建节点上下文
                NodeContext nodeContext = NodeContext.create(
                        context.getExecutionId(),
                        node.getId(),
                        context.getCurrentInputs()
                );
                nodeContext.setLogger(flowLogger);
                nodeContext.setVariables(context.getVariables());
                
                // 记录节点开始执行
                flowLogger.log(context.getExecutionId(), node.getId(), 
                        "开始执行节点: " + node.getName());
                
                // 执行节点
                NodeResult result = node.execute(nodeContext).get();
                
                // 记录节点执行结果
                if (result.isSuccess()) {
                    flowLogger.log(context.getExecutionId(), node.getId(), 
                            "节点执行成功: " + node.getName());
                    
                    // 更新全局变量
                    if (result.getOutputs() != null) {
                        context.getVariables().putAll(result.getOutputs());
                    }
                } else {
                    flowLogger.logError(context.getExecutionId(), node.getId(), 
                            "节点执行失败: " + node.getName(), result.getError());
                }
                
                // 保存节点执行结果
                context.getNodeResults().put(node.getId(), result);
                
                return result;
                
            } catch (Exception e) {
                flowLogger.logError(context.getExecutionId(), node.getId(), 
                        "节点执行异常: " + node.getName(), e);
                
                NodeResult errorResult = NodeResult.failure(node.getId(), 
                        "节点执行异常: " + e.getMessage(), e);
                context.getNodeResults().put(node.getId(), errorResult);
                
                return errorResult;
            }
        });
    }
    
    /**
     * 生成执行ID
     */
    private String generateExecutionId() {
        return "exec_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
    }
    
    /**
     * 流程执行上下文
     */
    private static class FlowExecutionContext {
        private final String executionId;
        private final FlowDefinition flowDefinition;
        private final Map<String, Object> inputs;
        private final Map<String, Object> variables = new ConcurrentHashMap<>();
        private final Map<String, NodeResult> nodeResults = new ConcurrentHashMap<>();
        
        public FlowExecutionContext(String executionId, FlowDefinition flowDefinition, Map<String, Object> inputs) {
            this.executionId = executionId;
            this.flowDefinition = flowDefinition;
            this.inputs = inputs != null ? inputs : Map.of();
        }
        
        public String getExecutionId() { return executionId; }
        public FlowDefinition getFlowDefinition() { return flowDefinition; }
        public Map<String, Object> getCurrentInputs() { return inputs; }
        public Map<String, Object> getVariables() { return variables; }
        public Map<String, NodeResult> getNodeResults() { return nodeResults; }
    }
} 